<?php

declare(strict_types=1);

/**
 * @Author:     Frank
 * @contact     frank_hhm@163.com
 * @Date:       2023-02-01 12:54:58
 * @Last Modified time: 2023-02-18 15:06:08
 */

namespace app\common\services\store\order;

use think\facade\Db;
use frank\base\BaseService;
use frank\exception\CommonException;
use frank\utils\helper\ArrayHelper;
use frank\utils\helper\StringHelper;
use frank\services\CacheService;

use app\common\services\store\OrderDeliveryService;

use app\common\services\user\UserAddressService;

use app\common\services\store\order\ExpressService;
use app\common\services\store\ShopService;

use app\common\dao\store\OrderDao;
use app\common\services\store\OrderService;

use app\common\enum\store\order\SourceEnum;
use app\common\enum\store\DeliveryTypeEnum;
use app\common\enum\pay\PayTypeEnum;
use app\common\enum\EnumFactory;


use app\common\factory\store\order\checkout\Factory as CheckoutFactory;
use app\common\factory\store\goods\source\Factory as StockFactory;
use app\common\services\store\order\PaySuccessService;

/**
 * 订单结算台服务类
 * Class CheckoutService
 */
class CheckoutService extends BaseService
{
    private $uid;

    private $user;

    private $order = [];

    private $goodsList = [];

    /**
     * 订单结算api参数
     */
    private $param = [
        'delivery_list' => [],                  // 支持配送方式
        'address_id'=>0,                        // 地址
        'delivery' => null,                     // 配送方式
        'linkname' => '',                        // 自提联系人
        'phone' => '',                          // 自提联系电话
        'remark' => '',                         // 买家留言
        'pay_type' =>  PayTypeEnum::WECHAT,     // 支付方式
    ];

    /**
     * 订单来源
     */
    private $orderSource = [
        'source' => SourceEnum::MASTER,
        'source_id' => 0,
    ];

    public function __construct(OrderDao $dao)
    {
		$this->dao = $dao;
    }


    /**
     * 设置结算台请求的参数
     */
    public function setParam($param)
    {
        $this->param['pay_type'] = sysconf("wechatpay_status") == 1? PayTypeEnum::WECHAT : PayTypeEnum::WALLET;
        $this->param = array_merge($this->param, $param);
        return $this->getParam();
    }

    /**
     * 获取结算台请求的参数
     */
    public function getParam()
    {
        return $this->param;
    }

    /**
     * 订单确认-结算台
     */
    public function onCheckout($user,$goodsList)
    {
        $this->user = $user;
        $this->uid = $user['id'];
        $this->goodsList = $goodsList;
        // 订单确认-立即购买
        return $this->checkout();
    }

    /**
     * 订单结算台
     */
    private function checkout()
    {
        // 整理订单数据
        $this->orderData = $this->getOrderData();
        // 验证商品状态, 是否允许购买
        $this->validateGoodsList();
        // 订单商品总数量
        $orderTotalNum = ArrayHelper::getArrayColumnSum($this->goodsList, 'total_num');

        // 计算订单的实际付款金额
        $this->setOrderGoodsPayPrice();
        // 处理配送方式
        if ($this->orderData['delivery'] == DeliveryTypeEnum::EXPRESS && $this->orderData['address_id']) {
            $this->setOrderExpress();
        }
        if ($this->orderData['delivery'] == DeliveryTypeEnum::SELFMENTION) {
            $this->param['shop_id'] > 0 && $this->orderData['extract_shop'] = ShopService::instance()->getShopDetail($this->param['shop_id']);
        }
        // 计算订单最终金额
        $this->setOrderPayPrice();

        // 返回订单数据
        return array_merge([
            'goods_list' =>array_values($this->goodsList),   // 商品信息
            'order_total_num' => $orderTotalNum,        // 商品总数量
            'has_error' => $this->hasError(),
            'error_msg' => $this->getError(),
        ], $this->orderData);

    }

    
    /**
     * 整理订单数据(结算台初始化)
     */
    private function getOrderData()
    {
        $addressService = UserAddressService::instance();
        $addresFilter = [];
        if($this->param['address_id']){
            $addresFilter['id'] = $this->param['address_id'];
        }
        $address = $addressService->getUserDefaultAddressDetail($this->uid,$addresFilter);

        // 获取全局配送模式
        $deliveryList = $this->getDeliveryList();
        return [
            'delivery_list'=>$deliveryList,
            // 配送类型
            'delivery' => $this->param['delivery']? $this->param['delivery'] : $deliveryList[0]['value'],
            // 默认地址
            'address' => $address?:0,
            'address_id'=> $address['id'] ?? 0,
            // 配送费用
            'express' => [
                'error'=> "",
                'is_express'=> 1,
                'is_free'=> 1,
                'price'=> "0.00",
            ],
            // 自提门店信息
            'extract_shop' => [],
            // 支付方式
            'pay_type' => $this->param['pay_type'],
        ];
    }

    /**
     * 获取配送模式
     */
    private function getDeliveryList(){
        $allDelivery = DeliveryTypeEnum::data();
        // 商品设置的配送模式
        $goodsDelivery = array_unique(ArrayHelper::getArray2Column($this->goodsList,'delivery_type'));
        $delivery = [];
        // 快递全局的设置
        if(sysconf("store_delivery_express") == 1 && in_array(DeliveryTypeEnum::EXPRESS, $goodsDelivery)){
            $delivery[] = EnumFactory::instance('store.delivery_type')->getItem(DeliveryTypeEnum::EXPRESS);
        }

        // delivery_type
        // 到店自提全局的设置   商品单独设置全部为空则隐藏
        if(sysconf("store_delivery_self_mention") == 1 && in_array(DeliveryTypeEnum::SELFMENTION, $goodsDelivery)){

            $delivery[] = EnumFactory::instance('store.delivery_type')->getItem(DeliveryTypeEnum::SELFMENTION);
        }

        if(!isset($delivery[0])){
            throw new CommonException("暂无配送方式");
        }
        return $delivery;
    }

    /**
     * 验证订单商品的状态
     */
    private function validateGoodsList()
    {
        $Checkout = CheckoutFactory::getFactory(
            $this->user,
            $this->goodsList,
            $this->orderSource['source']
        );
        $status = $Checkout->validateGoodsList();
        $status == false && $this->setError($Checkout->getError());
        return $status;
    }


    /**
     * 计算订单商品的实际付款金额
     */
    private function setOrderGoodsPayPrice()
    {
        // 商品总价
        foreach ($this->goodsList as &$goods) {
            $goods['total_pay_price'] = StringHelper::number2($goods['total_price']);
        }
        return true;
    }

    /**
     * 设置订单配送金额
     */
    private function setOrderExpress()
    {
        // 设置默认数据：配送费用
        Arrayhelper::attribute($this->goodsList, [
            'express_price' => 0,
        ], true);

        $address = $this->orderData['address'];

        // 当前用户收货城市id
        $cityId = $address ? $address['city_id'] : 0;
        
            // 初始化配送服务类
        $ExpressService = ExpressService::instance($cityId, $this->goodsList, SourceEnum::MASTER);
        // 订单总运费金额
        $this->orderData['express'] = $ExpressService->getExpress();

        return true;
    }

    /**
     * 设置订单的实际支付金额(含配送费)
     */
    private function setOrderPayPrice()
    {
        $this->orderData['order_total_price'] = StringHelper::number2(ArrayHelper::getArrayColumnSum($this->goodsList, 'total_pay_price'));
        // 订单实付款金额(订单金额 + 运费)
        $this->orderData['order_pay_price'] = StringHelper::number2(StringHelper::bcadd($this->orderData['order_total_price'], $this->orderData['express']['price']));
    }

    /**
     * 创建新订单
     */
    public function createOrder($order, $params)
    {
        // 表单验证
        if (!$this->validateOrderForm($order, $params['linkname'], $params['phone'])) {
            return false;
        }
        // 创建新的订单
        Db::startTrans();
        if($status = $this->createOrderEvent($order)){
            // 提交事务
            Db::commit();
        }else{
            // 回滚事务
            Db::rollback();
        }

        $this->order = $this->dao->model();
        // 余额支付标记订单已支付
        if ($status && $order['pay_type'] == PayTypeEnum::WALLET) {
            return OrderService::instance()->onPaymentByWallet($this->order);
        }
        return $status;
    }

    public function getOrder(){
        return $this->order;
    }

    /**
     * 创建订单事件
     */
    private function createOrderEvent($order)
    {
        // 新增订单记录
        $status = $this->createOrderData($order, $this->param['remark']);
        if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
            // 记录收货地址
            $this->saveOrderAddress($order['address']);
        } elseif ($order['delivery'] == DeliveryTypeEnum::SELFMENTION) {
            // 记录自提信息
            $this->saveOrderExtract($this->param['linkname'], $this->param['phone']);
        }
        // // 保存订单商品信息
        $this->saveOrderGoods($order);
        // 更新商品库存 (针对下单减库存的商品)
        $status = $this->updateGoodsStockNum($order);
        return $status;
    }

    /**
     * 新增订单记录
     */
    private function createOrderData($order, $remark = '')
    {
        // 订单数据
        $data = [
            'user_id' => $this->uid,
            'order_no' => $this->orderNo(),
            'order_total_price' => $order['order_total_price'],
            'order_pay_price' => $order['order_pay_price'],
            'delivery_type' => $order['delivery'],
            'buyer_remark' => trim($remark),
            'total_num' => $order['order_total_num'],
            'order_source' => $this->orderSource['source'],
            'order_source_id' => $this->orderSource['source_id'],
        ];

        if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
            $data['express_price'] = $order['express']['price'];
            $data['express_free'] = $order['express']['is_free'];
        } elseif ($order['delivery'] == DeliveryTypeEnum::SELFMENTION ) {
            // 生成提货码
            $data['extract_code'] = StringHelper::randString(4);
            $data['extract_shop_id'] = $this->param['shop_id'];
        }
        // 保存订单记录
        return $this->dao->save($data);
    }

    /**
     * 记录收货地址
     */
    private function saveOrderAddress($address)
    {
        if ($address['region_id'] == 0 && !empty($address['district'])) {
            $address['detail'] = $address['district'] . ' ' . $address['detail'];
        }
        return $this->dao->model()->address()->save([
            'member_id' => $this->uid,
            'name' => $address['name'],
            'phone' => $address['phone'],
            'province_id' => $address['province_id'],
            'city_id' => $address['city_id'],
            'region_id' => $address['region_id'],
            'detail' => $address['detail'],
        ]);
    }

    /**
     * 保存上门自提联系人
     */
    public function saveOrderExtract($linkname, $phone)
    {
        // 保存上门自提联系人(数据库)
        return $this->dao->model()->extract()->save([
            'linkname' => trim($linkname),
            'phone' => trim($phone),
            'user_id' => $this->dao->model()['user_id']
        ]);
    }

    /**
     * 保存订单商品信息
     */
    private function saveOrderGoods($order)
    {
        // 订单商品列表
        $goodsList = [];
        foreach ($order['goods_list'] as $goods) {
            $item = [
                'user_id' => $this->uid,
                'goods_id' => $goods['id'],
                'goods_name' => $goods['goods_name'],
                'goods_image' => !empty($goods['goods_sku']['goods_img'])?$goods['goods_sku']['goods_img']:$goods['goods_image'],
                // 'deduct_stock_type' => $goods['deduct_stock_type'],
                'bar_code' => $goods['goods_sku']['bar_code'],
                'spec_type' => $goods['spec_type']['value'],
                'goods_sku_id' => $goods['goods_sku']['id'],
                'sku_attr' => $goods['goods_sku']['sku_attr'],
                'sku_attr_text' => $goods['goods_sku']['sku_attr_text'],
                'price' => $goods['goods_sku']['price'],
                'market_price' => $goods['goods_sku']['market_price'],
                'cost_price' => $goods['goods_sku']['cost_price'],
                'weight' => $goods['goods_sku']['weight'],
                'volume' => $goods['goods_sku']['volume'],
                'total_num' => $goods['total_num'],
                'total_price' => $goods['total_price'],
                'total_pay_price' => $goods['total_pay_price'],
                'source' => $this->orderSource['source'],
                'source_id' => $this->orderSource['source_id']
            ];
            $goodsList[] = $item;
        }
        return $this->dao->model()->goods()->saveAll($goodsList);
    }

    /**
     * 表单验证 (订单提交)
     */
    private function validateOrderForm(&$order, $linkname, $phone)
    {
        if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
            if (empty($order['address'])) {
                $this->error = '请先选择收货地址';
                return false;
            }
        }

        if ($order['delivery'] == DeliveryTypeEnum::SELFMENTION) {
            if (empty($order['extract_shop'])) {
                $this->error = '请先选择自提门店';
                return false;
            }
            if (empty($linkname) || empty($phone)) {
                $this->error = '请填写联系人和电话';
                return false;
            }
        }

        // 余额支付时判断用户余额是否足够
        if ($order['pay_type'] == PayTypeEnum::WALLET) {
            if ($this->user['balance'] < $order['order_pay_price']) {
                $this->error = '您的余额不足，无法使用余额支付';
                return false;
            }
        }
        return true;
    }

    /**
     * 更新商品库存 (针对下单减库存的商品)
     */
    private function updateGoodsStockNum($order)
    {
        $factory = StockFactory::getFactory($this->orderSource['source']);
        if(!$status = $factory->updateGoodsStock($order['goods_list'],$this->orderSource['source_id'])){
            $this->error = $factory->getError();
        }
        return $status;
    }

    /**
     * 构建支付请求的参数
     */
    public function onOrderPayment($user, $payType)
    {
        return ($payType == PayTypeEnum::WECHAT) ? OrderService::instance()->onPaymentByWechat($user,$payType,$this->order) : [];
    }
}
